Network based storage, or simply “network storage”, is a common approach to backing up data, making large amounts of data accessible to multiple users, and other purposes. In a network storage environment, a storage server makes data available to client (host) systems by presenting or exporting to the clients one or more logical containers of data (or simply, “data objects”). There are various forms of network storage, including network attached storage (NAS) and storage area network (SAN). In a NAS context, a storage server services file-level requests from clients, whereas in a SAN context a storage server services block-level requests. Some storage servers are capable of servicing both file-level requests and block-level requests.
There are several trends that are relevant to network storage technology. The first is that the amount of data being stored within a typical enterprise is approximately doubling from year to year. Second, the number of clients that the storage server can serve simultaneously has also been steadily increasing. As a result of the increase in stored data and the increase in the number of clients accessing the stored data, a vast majority of the storage server's computing resources is allocated to servicing, for example, read and write requests received from the clients.
In traditional storage systems, the storage server stores data pertaining to each data object (e.g., a file) in the form of multiple “direct” data-blocks that contain the actual user data of the data object. The storage server typically uses a hierarchical structure (e.g., a buffer tree) that uses multiple levels of data-blocks to represent each data object. For example, “indirect” data-blocks in a buffer tree associated with a data object typically include pointers for locating direct data-blocks of the data object at a lower level of the buffer tree.
As a result of the multiple levels of hierarchy, a traditional storage server commonly uses multiple read operations (i.e., multiple I/O operations) to read a data object. For example, when a data object is represented using two levels of hierarchy (i.e., a first level containing indirect data-blocks and a second level that contains direct data-blocks), the storage server uses two read operations: a first read operation to read the indirect data-blocks (to identify the location of the direct-data blocks), and a second read operation to read the second level direct data-blocks. These multiple read operations for reading a data object significantly consume processing resources of the storage server, which can significantly impact performance, especially in a system that has a heavy read workload.